package main

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"os/signal"
	"regexp"
	"syscall"
	"time"

	global "developer_tools/globals"
	"developer_tools/internal/pwd"

	"github.com/wailsapp/wails/v2/pkg/runtime"
	"golang.org/x/crypto/ssh"
)

var log_ = global.Logger
var storeList = pwd.NewStoreList()

// StripANSI removes ANSI escape sequences from the input string.
func StripANSI(input string) string {
	// 正则表达式匹配 ANSI 转义序列
	ansiRegex := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
	return ansiRegex.ReplaceAllString(input, "")
}

func ConnectSsh(ctx context.Context, username, password, host string, port int) (*ssh.Client, error) {
	config := &ssh.ClientConfig{
		User: username,
		Auth: []ssh.AuthMethod{
			ssh.Password(password),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Timeout:         10 * time.Second,
	}

	// 连接ssh服务器
	client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), config)
	if err != nil {
		log_.Errorf("%s: %s", global.ConnectSSHServerFailed, err)
		runtime.EventsEmit(ctx, "error", global.ConnectSSHServerFailed)
		return nil, err
	}

	return client, nil
}

func _session_wait(ctx context.Context, session *ssh.Session) {
	// 等待命令执行完成
	err := session.Wait()
	if err != nil {
		log_.Warnf("error type: %T", err)
		if exitError, ok := err.(*ssh.ExitError); ok {
			if exitError.ExitStatus() == 141 {
				log_.Warn("Ignoring SIGPIPE signal (io.ErrClosedPipe)")
			} else {
				log_.Errorf("%s - [Unexpected error]%s: %d", global.CommandFailed, exitError.Error(), exitError.ExitStatus())
				runtime.EventsEmit(ctx, "error", fmt.Sprintf("%s, ssh exit code: %d", global.CommandFailed, exitError.ExitStatus()))
			}
		} else {
			if missingError, ok := err.(*ssh.ExitMissingError); ok {
				log_.Warnf("Ignoring ExitMissingError: %s", missingError.Error())
			} else {
				log_.Errorf("%s: %s", global.CommandFailed, err)
				runtime.EventsEmit(ctx, "error", global.CommandFailed)
			}
		}

	} else {
		runtime.EventsEmit(ctx, "command-end", global.CommandCompleted)
	}
}

func DoShell(app *App, client *ssh.Client, shell string, supportStream bool) {
	log_.Debugf("Start shell: %s. Support stream: %v. Max buffer size: %d Bytes", shell, supportStream, global.MaxBufferSize)
	ctx := app.ctx

	// 建立SSH会话
	session, err := client.NewSession()
	if err != nil {
		log_.Errorf("%s: %s", global.CreateSSHSessionFailed, err)
		runtime.EventsEmit(ctx, "error", global.CreateSSHSessionFailed)
		return
	}
	defer session.Close()

	stdout, err := session.StdoutPipe()
	if err != nil {
		log_.Errorf("%s: %s", global.GetPipeoutFailed, err)
		runtime.EventsEmit(ctx, "error", global.GetPipeoutFailed)
		return
	}

	stderr, err := session.StderrPipe()
	if err != nil {
		log_.Errorf("%s: %s", global.GetPipeErrFailed, err)
		runtime.EventsEmit(ctx, "error", global.GetPipeErrFailed)
		return
	}

	// 执行脚本
	err = session.Start(shell)
	if err != nil {
		log_.Errorf("%s: %s", global.ExecuteCommandFailed, err)
		runtime.EventsEmit(ctx, "error", global.ExecuteCommandFailed)
		return
	}

	// 创建一个 Channel 用于合并输出
	outputChan := make(chan string)
	// 读取标准输出
	go func() {
		scanner := bufio.NewScanner(stdout)
		buf := make([]byte, global.MaxBufferSize) // 1MB buffer
		scanner.Buffer(buf, len(buf))
		for scanner.Scan() {
			line := scanner.Text()
			outputChan <- line
		}
	}()

	// 读取标准错误输出
	go func() {
		scanner := bufio.NewScanner(stderr)
		buf := make([]byte, global.MaxBufferSize) // 1MB buffer
		scanner.Buffer(buf, len(buf))
		for scanner.Scan() {
			line := scanner.Text()
			outputChan <- line
		}
	}()

	// 处理合并后的输出
	go func() {
		for line := range outputChan {
			// 将日志通过 Wails 推送到前端
			strip_ansi_line := StripANSI(line)
			runtime.EventsEmit(ctx, "log", strip_ansi_line)
		}
	}()

	// // 逐行读取日志并输出
	// go func() {
	// 	scanner := bufio.NewScanner(stdout)
	// 	buf := make([]byte, MaxBufferSize) // 1MB buffer
	// 	scanner.Buffer(buf, len(buf))
	// 	for scanner.Scan() {
	// 		line := scanner.Text() // 获取每一行日志
	// 		log_.Debug(line)

	// 		// 将日志通过 Wails 推送到前端
	// 		strip_ansi_line := StripANSI(line)
	// 		runtime.EventsEmit(ctx, "log", strip_ansi_line)
	// 	}

	// 	// 检查扫描是否有错误
	// 	if err := scanner.Err(); err != nil {
	// 		log_.Errorf("%s: %s", GetScanLineFailed, err)
	// 		runtime.EventsEmit(ctx, "error", GetScanLineFailed)
	// 	}
	// }()

	// go func() {
	// 	scanner := bufio.NewScanner(stderr)
	// 	buf := make([]byte, MaxBufferSize) // 1MB buffer
	// 	scanner.Buffer(buf, len(buf))
	// 	for scanner.Scan() {
	// 		line := scanner.Text() // 获取每一行日志
	// 		log_.Debug(line)

	// 		// 将日志通过 Wails 推送到前端
	// 		strip_ansi_line := StripANSI(line)
	// 		runtime.EventsEmit(ctx, "log", strip_ansi_line)
	// 	}

	// 	// 检查扫描是否有错误
	// 	if err := scanner.Err(); err != nil {
	// 		log_.Errorf("%s: %s", GetScanLineFailed, err)
	// 		runtime.EventsEmit(ctx, "error", GetScanLineFailed)
	// 	}
	// }()

	log_.Debugf("Current OS: %s", global.CurrentOS)
	switch global.CurrentOS {
	case "windows":
		app.currentSession = session
		if supportStream {
			log_.Debug("Log stream started, waiting for ssh signal to stop...")
			_session_wait(ctx, session)
		} else {
			log_.Debug("Log stream started, waiting for command to complete...")
			// 等待命令完成
			_session_wait(ctx, session)
		}
	default:
		if supportStream {
			log_.Debug("Log stream started, waiting for signal to stop...")
			// 监听系统信号以停止日志流
			stopChan := make(chan os.Signal, 2)
			signal.Notify(stopChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
			// 等待停止信号
			<-stopChan

			signal.Stop(stopChan)
			session.Signal(ssh.SIGINT)

			// 发送日志流结束信号
			runtime.EventsEmit(ctx, "command-end", "Log stream ended by signal")
		} else {
			log_.Debug("Log stream started, waiting for command to complete...")
			// 等待命令完成
			_session_wait(ctx, session)
		}
	}
}

func StopLogStreamWin(app *App) {
	if app.currentSession != nil {
		// 尝试发送 SIGINT 信号
		if err := app.currentSession.Signal(ssh.SIGINT); err != nil {
			log_.Errorf("Failed to send SIGINT signal: %v", err)
		} else {
			log_.Debug("SIGINT signal sent successfully")
		}

		// 等待 500 毫秒，确保信号被处理
		time.Sleep(500 * time.Millisecond)

		// 关闭会话
		if err := app.currentSession.Close(); err != nil {
			log_.Errorf("Failed to close SSH session: %v", err)
		} else {
			log_.Debug("SSH session closed successfully")
		}

		// 清理当前会话
		app.currentSession = nil
	} else {
		log_.Warn("No active SSH session to stop")
	}

	// 通知前端日志流已停止
	log_.Debug(global.LogStreamStopped)
	runtime.EventsEmit(app.ctx, "command-end", global.LogStreamStopped)
}

func StopLogStreamUnix(ctx context.Context) {
	// 发送停止信号
	pid := os.Getpid()
	process, err := os.FindProcess(pid)
	if err != nil {
		log_.Errorf("%s: %s", global.FindProcessFailed, err)
		runtime.EventsEmit(ctx, "error", global.FindProcessFailed)
		return
	}
	err = process.Signal(syscall.SIGINT)
	if err != nil {
		log_.Errorf("%s: %s", global.SendSignalFailed, err)
		runtime.EventsEmit(ctx, "error", global.SendSignalFailed)
		return
	}
}

// RequestPseudoTerminal requests a pseudo-terminal for the given SSH session.
// It sets up the terminal modes, connects the session to the standard input/output/error streams,
// and waits for the command execution to complete.
func RequestPseudoTerminal(ctx context.Context, session *ssh.Session) error {
	// 请求一个伪终端
	modes := ssh.TerminalModes{
		ssh.ECHO:          0,     // 禁用回显
		ssh.TTY_OP_ISPEED: 14400, // 输入速度 14.4kbaud
		ssh.TTY_OP_OSPEED: 14400, // 输出速度 14.4kbaud
	}

	if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
		log_.Errorf("%s: %s", global.RequestPseudoTerminalFailed, err)
		runtime.EventsEmit(ctx, "error", global.RequestPseudoTerminalFailed)
	}

	// 将标准输入、输出和错误连接到会话
	session.Stdin = os.Stdin
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr

	_session_wait(ctx, session)
	return nil
}

// GetHostList获取所有主机列表
func GetHostList() []string {
	return storeList.GetStoreList()
}

// 保存成功连接的SSH服务器信息
func SaveConnectedSSHHost(username, password, host string, port int) {
	storeList.WriteStore(pwd.Store{
		Username: username,
		Password: password,
		Host:     host,
		Port:     port,
	})
}

// 获取指定主机信息
func GetHostInfo(host string, port int) pwd.Store {
	return storeList.GetStore(host, port)
}

// DeleteSSHHost deletes a stored SSH host record by host and port
func DeleteSSHHost(host string, port int) error {
	// Check if the host exists before attempting to delete
	store := storeList.GetStore(host, port)
	if store.Host == "" {
		log_.Warnf("Attempted to delete non-existent host record: %s:%d", host, port)
		return fmt.Errorf("host record not found: %s:%d", host, port)
	}

	// Delete the host record
	err := storeList.DeleteStore(host, port)
	if err != nil {
		log_.Errorf("Failed to delete host record %s:%d: %v", host, port, err)
		return err
	}

	log_.Infof("Successfully deleted host record: %s:%d", host, port)
	return nil
}

// CheckSSHAlive attempts to establish a connection to an SSH server to verify if the host is reachable.
// It takes the host address and port as input and returns a boolean indicating whether the SSH connection was successful.
// The function uses stored host credentials and attempts to dial the SSH server with a 10-second timeout.
// Returns true if the connection is successful, false otherwise.
func CheckSSHAlive(host string, port int) bool {
	info := GetHostInfo(host, port)

	config := &ssh.ClientConfig{
		User: info.Username,
		Auth: []ssh.AuthMethod{
			ssh.Password(info.Password),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		Timeout:         10 * time.Second,
	}

	// 连接ssh服务器
	client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), config)
	if err != nil {
		log_.Errorf("%s: %s", global.ConnectSSHServerFailed, err)
		return false
	}
	defer client.Close()

	return true
}
